﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
using System.Collections;
using System.IO;
//31,4,32,4,33,4,31,4,31,4,32,4,33,4,31,4,33,4,34,4,35,8,33,4,34,4,35,8 
//21,4,25,4,21,4,25,4,21,4,25,4,21,4,25,4,21,4,25,4,21,4,25,4,21,4,25,4,21,4,25,4 
namespace music
{
    public partial class Form1 : Form
    {
        MidiBase Midi = new MidiBase();
        public Form1()
        {
            InitializeComponent();
            cbxMelodyTimbre.Items.Clear();
            cbxAccompanyTimbre.Items.Clear();
            int i = 0;
            foreach (string x in Enum.GetNames(typeof(MidiToneType)))
            {
                cbxMelodyTimbre.Items.Add("(" + i.ToString("000") + ") " + x);
                cbxAccompanyTimbre.Items.Add("(" + i.ToString("000") + ") " + x);
                i++;
            }
            cbxMelodyTimbre.SelectedIndex = 0;
            cbxAccompanyTimbre.SelectedIndex = 0;

            cbxMelodyTone.Items.Clear();
            cbxAccompanyTone.Items.Clear();
            foreach (string x in Enum.GetNames(typeof(DatumTone)))
            {
                cbxMelodyTone.Items.Add(x);
                cbxAccompanyTone.Items.Add(x);
            }
            cbxMelodyTone.SelectedIndex = 0;
            cbxAccompanyTone.SelectedIndex = 0;
        }
        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void btnPlay_Click(object sender, EventArgs e)
        {
            int beat = 0;
            try
            {
                beat = Convert.ToInt32(this.txtBeat.Text.ToString());
            }
            catch
            {
                MessageBox.Show("节拍设置有误！");
                return;
            }

            //旋律设置
            MusicCode melodyMusicCode = new MusicCode();
            melodyMusicCode.Channel = 1;
            melodyMusicCode.Timbre = (byte)(MidiToneType)Enum.ToObject(typeof(MidiToneType), cbxMelodyTimbre.SelectedIndex);
            melodyMusicCode.RhythmCount = beat;//节奏，每分钟多少拍
            melodyMusicCode.Code = this.txtMelody.Text.ToString().Replace("\r\n", ",").Replace(".", ",").Trim(',');
            melodyMusicCode.Datum = this.cbxMelodyTone.SelectedIndex;//乐谱中的音调
            if (melodyMusicCode.Code.Contains(','))
            {
                transformMusicCode(ref melodyMusicCode);
            }

            //伴奏
            MusicCode accompanyMusicCode = new MusicCode();
            accompanyMusicCode.Channel = 2;
            accompanyMusicCode.Timbre = (byte)(MidiToneType)Enum.ToObject(typeof(MidiToneType), cbxAccompanyTimbre.SelectedIndex);
            accompanyMusicCode.RhythmCount = beat;//节奏，每分钟多少拍
            accompanyMusicCode.Code = this.txtAccompany.Text.ToString().Replace("\r\n", ",").Replace(".", ",").Trim(',');
            accompanyMusicCode.Datum = this.cbxAccompanyTone.SelectedIndex;//乐谱中的音调
            if (accompanyMusicCode.Code.Contains(','))
            {
                transformMusicCode(ref accompanyMusicCode);
            }

            Thread Play = new Thread(new ParameterizedThreadStart(PlayMelodyMusic));
            Play.Start(melodyMusicCode);

            Thread Play1 = new Thread(new ParameterizedThreadStart(PlayMelodyMusic));
            Play1.Start(accompanyMusicCode);
        }

        /// <summary>
        /// 播放音乐文件
        /// </summary>
        /// <param name="ObjMusicCode"></param>
        private void PlayMelodyMusic(object ObjMusicCode)
        {
            MusicCode musicCode = ObjMusicCode as MusicCode;
            Midi.SetTimbre(musicCode.Timbre, musicCode.Channel);//设置音色
            for (int i = 0; i < musicCode.ALmusic.Count; i++)
            {
                if (Convert.ToByte(musicCode.ALmusic[i]) > 0)
                {
                    Midi.PlayMusic(Convert.ToByte(musicCode.ALmusic[i]), Convert.ToInt32(musicCode.ALbeat[i]), musicCode.Channel);
                }
                else
                {
                    Thread.Sleep(Convert.ToInt32(musicCode.ALbeat[i]));
                }
            }
        }

        private void cbxMelodyTimbre_SelectedIndexChanged(object sender, EventArgs e)
        {
            Midi.SetTimbre((byte)(MidiToneType)Enum.ToObject(typeof(MidiToneType), cbxMelodyTimbre.SelectedIndex), 1);
        }

        private void cbxAccompanyTimbre_SelectedIndexChanged(object sender, EventArgs e)
        {
            Midi.SetTimbre((byte)(MidiToneType)Enum.ToObject(typeof(MidiToneType), cbxAccompanyTimbre.SelectedIndex), 2);
        }

        private void transformMusicCode(ref MusicCode musicCode)
        {
            string[] MusicCodeList = musicCode.Code.ToString().Split(',');
            ArrayList ALmusic = new ArrayList();//声音频率的集合
            ArrayList ALbeat = new ArrayList();//声音播放时长
            int[] DatumTone = { 0, 2, 4, 5, 7, 9, 11 };
            for (int i = 0; i < MusicCodeList.Length; i++)
            {
                if (i % 2 == 0)
                {
                    try
                    {
                        int j = Convert.ToInt32(MusicCodeList[i].Substring(0, 1));
                        int k = Convert.ToInt32(MusicCodeList[i].Substring(1, 1));
                        ALmusic.Add(36 + 12 * (j - 1) + DatumTone[musicCode.Datum] + DatumTone[k - 1]);
                    }
                    catch
                    {
                        ALmusic.Add(0);
                    }
                }
                else if (i % 2 == 1)
                {
                    double time = Convert.ToDouble(MusicCodeList[i]) / 4 * 60 / Convert.ToDouble(musicCode.RhythmCount) * 1000;
                    ALbeat.Add(time);
                }
            }
            musicCode.ALmusic = ALmusic;
            musicCode.ALbeat = ALbeat;
        }
    }


    public class MusicCode
    {
        int rhythmCount = 120;//默认一分钟120拍
        int rhythmLength = 4;//默认一小节4拍
        byte channel; //MIDI通道
        byte timbre;//音色
        int datum;//
        string code;

        ArrayList aLmusic;
        ArrayList aLbeat;

        public byte Channel { get => channel; set => channel = value; }
        public byte Timbre { get => timbre; set => timbre = value; }
        public int RhythmCount { get => rhythmCount; set => rhythmCount = value; }
        public string Code { get => code; set => code = value; }
        public int Datum { get => datum; set => datum = value; }
        public int RhythmLength { get => rhythmLength; set => rhythmLength = value; }

        public ArrayList ALmusic { get => aLmusic; set => aLmusic = value; }
        public ArrayList ALbeat { get => aLbeat; set => aLbeat = value; }

    }
}
